package com.hfy.music.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hfy.model.Es.MusicEs;
import com.hfy.model.po.music.MusicPo;
import com.hfy.model.vo.AlbumVo;
import com.hfy.music.mapper.MusicMapper;
import com.hfy.music.mapper.MusicianMapper;
import com.hfy.music.service.MusicService;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import result.Result;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static constants.EsConstants.*;
import static constants.OtherConstants.PAGE_NUM;

/**
 * @ author 韩
 * time: 2024/5/21 4:10
 */

@Service
public class MusicServiceImpl extends ServiceImpl<MusicMapper, MusicPo> implements MusicService {


    @Autowired
    private MusicMapper findMusicMapper;

    @Autowired
    private MusicianMapper musicianMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public Result queryByPage(int pageNum) {
        int offset = (pageNum-1) * PAGE_NUM;
        //要指定两个值 一个是偏移量，一个是页数，默认一页15条记录
        List<MusicPo> musicList = findMusicMapper.queryByPage(offset,PAGE_NUM);
        return Result.ok(musicList);
    }

    @Override
    public Result queryByMusicKey(String key, Integer pageNum) {

        if (pageNum < 1) return Result.error("页数不能比1小");
        if (StringUtils.isBlank(key)) return Result.error("不能进行音乐查询，关键词为空");

        key = key.trim();
        String field = key.length() == 1 ? ES_MUSIC_FIELD_NAME + '_' : ES_MUSIC_FIELD_NAME;


//        // 直接进行模糊查询 我想的是把name字段musician，album合成一个字符串去查
//        List<MusicVo> musicList = findMusicMapper.queryByMusicKey(key);
        // 用es替换 使用的技术 高亮 还有普通查询 没有条件的限制 不需要复合查询

        // 1. 先创建request对象
        SearchRequest request = new SearchRequest(ES_MUSIC_INDEX);
        // 2. 组织DSL参数
        request.source().query(QueryBuilders.matchQuery(ES_MUSIC_FIELD_NAME,key));
        // 3. 分页配置 固定的页数是一个常量，默认为10 ，在前端页面初始化的时候 会自动调用一次 前端会缓存一个页数数据 通过查看更多来修改分页数据
        request.source().from((pageNum-1) * ES_PAGE_SIZE).size(ES_PAGE_SIZE);

        // 4. 查询配置 这个是音乐名字的关键字查询
        request.source().query(QueryBuilders.matchQuery(field,key));
        // 5. 高亮配置
        request.source().highlighter(new HighlightBuilder()
                .field(field).requireFieldMatch(false)
        );

        // 6.发送请求，得到响应结果
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 7. 对请求的结果进行解析
            SearchHits searchHits = response.getHits();
            // 8. 这个就是搜索到的数据 但不够 因为使用了高亮功能 其他字段保留 查询的字段要进行替换 在这里是name
            SearchHit[] hits = searchHits.getHits();
            List<SearchHit> list = Arrays.asList(hits);
            ArrayList<MusicPo> musicList = new ArrayList<>();
            list.forEach((hit) -> {

                MusicPo musicPo = JSON.parseObject(hit.getSourceAsString(), MusicPo.class);
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                // 9. 高亮处理
                if (!CollectionUtils.isEmpty(highlightFields)) {
                    HighlightField highlightField = highlightFields.get(field);
                    if (highlightField != null) {
                        musicPo.setName(highlightField.getFragments()[0].toString());
                    }
                }
                musicList.add(musicPo);
            });



            if (musicList.size() == 0) {
                return Result.error("抱歉 没有找到结果");
            }
            return Result.ok(musicList);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.error("ES发生错误");
    }

    @Override
    public Result queryByAlbumKey(String key, Integer pageNum) {
        if (pageNum < 1) return Result.error("页数不能比1小");
        if (StringUtils.isBlank(key)) return Result.error("不能进行专辑查询，关键词为空");

        key = key.trim();
        String field = key.length() == 1 ? ES_MUSIC_FIELD_NAME + '_' : ES_MUSIC_FIELD_NAME;


//        // 直接进行模糊查询 我想的是把name字段musician，album合成一个字符串去查
//        List<MusicVo> musicList = findMusicMapper.queryByMusicKey(key);
        // 用es替换 使用的技术 高亮 还有普通查询 没有条件的限制 不需要复合查询

        // 1. 先创建request对象
        SearchRequest request = new SearchRequest(ES_MUSIC_INDEX);
        // 2. 组织DSL参数
        request.source().query(QueryBuilders.matchQuery(ES_MUSIC_FIELD_NAME,key));
        // 3. 分页配置 固定的页数是一个常量，默认为10 ，在前端页面初始化的时候 会自动调用一次 前端会缓存一个页数数据 通过查看更多来修改分页数据
        request.source().from((pageNum-1) * ES_PAGE_SIZE).size(ES_PAGE_SIZE);

        // 4. 查询配置 这个是音乐名字的关键字查询

        request.source().query(QueryBuilders.matchQuery(field,key));
        // 5. 高亮配置
        request.source().highlighter(new HighlightBuilder()
                .field(field).requireFieldMatch(false)
        );


        // 6.发送请求，得到响应结果
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 7. 对请求的结果进行解析
            SearchHits searchHits = response.getHits();
            // 8. 这个就是搜索到的数据 但不够 因为使用了高亮功能 其他字段保留 查询的字段要进行替换 在这里是name
            SearchHit[] hits = searchHits.getHits();
            List<SearchHit> list = Arrays.asList(hits);
            ArrayList<AlbumVo> albumList = new ArrayList<>();
            list.forEach((hit) -> {

                // 逻辑要改写
                MusicEs musicEs = JSON.parseObject(hit.getSourceAsString(), MusicEs.class);
                AlbumVo albumVo = new AlbumVo();
                albumVo.setCover(musicEs.getCover());
                albumVo.setMusician(musicEs.getMusician());
                albumVo.setCreateTime(musicEs.getCreateTime());

                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                // 9. 高亮处理
                if (!CollectionUtils.isEmpty(highlightFields)) {
                    HighlightField highlightField = highlightFields.get(field);
                    if (highlightField != null) {
                        albumVo.setAlbum(highlightField.getFragments()[0].toString());
                    }
                }
                albumList.add(albumVo);
            });

            if (albumList.size() == 0) {
                return Result.error("抱歉 没有找到结果");
            }
            return Result.ok(albumList);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.error("ES发生错误");

    }
}
